using System.Collections.Generic;
using System.Text;
using System;
using Dorm.Helpers;
using Dorm.Maps;

namespace Dorm.QueryObject
{
    public class Insert
    {
        protected string EntityName { get; set; }
        protected object Entity { get; set; }
        protected List<Parameter> PropertyValues { get; set; }
        protected bool ShouldGetID { get; set; }

        public Insert()
        {
            PropertyValues = new List<Parameter>();
        }

        public Insert Into(string entityName)
        {
            EntityName = entityName;
            return this;
        }

        public Insert Into<T>()
        {
            EntityName = typeof(T).Name;
            return this;
        }

        public Insert Values(object entity)
        {
            Entity = entity;
            var entityInfo = new EntityInfo(entity);

            var entityMaps = MapLocator.GetMap(entity.GetType());

            PropertyValues = new List<Parameter>();

            foreach (var mappedProperty in entityMaps)
            {
                if (entityInfo.GetValue(mappedProperty.PropertyName) == null)
                    continue;

                if (mappedProperty.MappingType == MappedProperty.MappingTypes.Simple)
                {
                    object propertyValue = entityInfo.GetValue(mappedProperty.PropertyName);

                    if (propertyValue == null)
                        continue;

                    if (mappedProperty.PropertyType.IsEnum)
                        propertyValue = Convert.ToInt32(propertyValue);

                    PropertyValues.Add(new Parameter 
                    { 
                        PropertyName = mappedProperty.PropertyName,
                        PropertyValue = propertyValue
                    });
                }
                else if (mappedProperty.MappingType == MappedProperty.MappingTypes.Reference)
                {
                    var reference = entityInfo.GetValue(mappedProperty.PropertyName);

                    if (reference == null)
                        continue;

                    var referenceInfo = new EntityInfo(reference);

                    PropertyValues.Add(new Parameter
                    {
                        PropertyName = mappedProperty.PropertyName + "ID",
                        PropertyValue = referenceInfo.ID
                    });
                }
                else if (mappedProperty.MappingType == MappedProperty.MappingTypes.Component)
                {
                    var componentInfo = new EntityInfo(entityInfo.GetValue(mappedProperty.PropertyName));

                    var componentProperties = MapLocator.GetMap(componentInfo.EntityType);

                    foreach(var componentProperty in componentProperties)
                    {
                        if (componentProperty.MappingType == MappedProperty.MappingTypes.Simple)
                        {
                            var componentValue = componentInfo.GetValue(componentProperty.PropertyName);

                            if (componentValue == null)
                                continue;

                            PropertyValues.Add(new Parameter
                            {
                                PropertyName = mappedProperty.PropertyName + componentProperty.PropertyName,
                                PropertyValue = componentValue
                            });
                        }
                        else if (componentProperty.MappingType == MappedProperty.MappingTypes.Reference)
                        {
                            var componentValue = componentInfo.GetValue(componentProperty.PropertyName);

                            if (componentValue == null)
                                continue;

                            PropertyValues.Add(new Parameter
                            {
                                PropertyName = mappedProperty.PropertyName + componentProperty.PropertyName + "ID",
                                PropertyValue = componentProperty.PropertyType.GetProperty("ID")
                                    .GetValue(componentValue, null)
                            });
                        }
                    }
                }
            }

            return this;
        }

        public Insert Value(string propertyName, object propertyValue)
        {
            PropertyValues.Add(new Parameter {PropertyName = propertyName, PropertyValue = propertyValue});
            return this;
        }

        public Insert ReturnID()
        {
            ShouldGetID = true;
            return this;
        }

        public override string ToString()
        {
            var expression = new StringBuilder();

            expression.Append("INSERT INTO ");
            expression.AppendLine(EntityName);

            expression.AppendLine(" (" + PropertyValues[0].PropertyName);
            for (int i = 1; i < PropertyValues.Count; i++)
            {
                expression.AppendLine(" ," + PropertyValues[i].PropertyName);
            }
            expression.AppendLine(" ) VALUES");

            expression.AppendLine(" (" + PropertyValues[0].PropertyValue);
            for (int i = 1; i < PropertyValues.Count; i++)
            {
                expression.AppendLine(" ," + PropertyValues[i].PropertyValue);
            }
            expression.AppendLine(" ) ");

            if (ShouldGetID)
                expression.AppendLine(" SELECT SCOPE_IDENTITY()");

            return expression.ToString();
        }
    }
}
